package org.raymond.iworks.admin.service.impl;


import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.raymond.iworks.admin.service.ITSysPermissionService;
import org.raymond.iworks.apis.common.ErrorCode;
import org.raymond.iworks.apis.exception.BaseException;
import org.raymond.iworks.apis.vo.permission.PermissionNodeVO;
import org.raymond.iworks.repository.entity.TRolePermissionRel;
import org.raymond.iworks.repository.entity.TSysPermission;
import org.raymond.iworks.repository.entity.enums.StateEnum;
import org.raymond.iworks.repository.repository.TRolePermissionRelRepository;
import org.raymond.iworks.repository.repository.TSysPermissionRepository;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Example;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author raymond
 * @version V1.0
 * @Description: TODO
 */
@Slf4j
@Service
public class TSysPermissionServiceImpl implements ITSysPermissionService {
    @Autowired
    private TSysPermissionRepository tSysPermissionRepository;
    @Autowired
    private TRolePermissionRelRepository tRolePermissionRelRepository;

    @Override
    public List<TSysPermission> getsAssociatedPermissionByRoleIds(Set<Long> roleIds) {
        if(CollectionUtils.isEmpty(roleIds)) {
            return null;
        }
        List<TRolePermissionRel> rolePermissionRels = tRolePermissionRelRepository.findAllById(roleIds);
        if(CollectionUtils.isEmpty(rolePermissionRels)) {
            return null;
        }
        Set<Long> directPermissionIdSet = rolePermissionRels.stream().mapToLong(TRolePermissionRel::getPermissionId).boxed().collect(Collectors.toSet());
        List<TSysPermission> directPermissionList = tSysPermissionRepository.findAllById(directPermissionIdSet);
        if(CollectionUtils.isEmpty(directPermissionList)) {
            return null;
        }
        directPermissionList = directPermissionList.stream()
                .filter(e->e.equals(StateEnum.NORMAL.getCode()))
                .toList();
        return directPermissionList;
    }

    @Override
    public PermissionNodeVO getTreeByRoleId(Long roleId) {
        PermissionNodeVO permissionTree = tree();
        if(permissionTree==null || CollectionUtils.isEmpty(permissionTree.getChildren())){
            String message = "系统未配置任何权限";
            throw new BaseException(ErrorCode.NOT_CONFIGURED, message);
        }

        TRolePermissionRel rel = TRolePermissionRel.builder().roleId(roleId).build();
        List<TRolePermissionRel> rpList = tRolePermissionRelRepository.findAll(Example.of(rel));
        if(CollectionUtils.isNotEmpty(rpList)){
            rpList.stream().forEach(e->{
                associateRole(e, permissionTree.getChildren());
            });
        }
        return permissionTree;
    }

    @Override
    public PermissionNodeVO tree() {
        List<TSysPermission> list = tSysPermissionRepository.findAll();

        List<PermissionNodeVO> all = list.stream().map(e -> {
            PermissionNodeVO node = new PermissionNodeVO();
            BeanUtils.copyProperties(e, node);
            return node;
        }).collect(Collectors.toList());

        Long topId = 0L;
        List<PermissionNodeVO> firstNodes = child(topId, all);
        PermissionNodeVO top = new PermissionNodeVO();
        top.setId(topId);
        top.setChildren(firstNodes);
        return top;
    }

    private List<PermissionNodeVO> child(Long parentId, List<PermissionNodeVO> all){
        List<PermissionNodeVO> children = all.stream().filter(e->e.getParentId().equals(parentId)).collect(Collectors.toList());
        if(CollectionUtils.isNotEmpty(children)) {
            children.stream().forEach(c -> {
                List<PermissionNodeVO> childChildRen = child(c.getId(), all);
                c.setChildren(childChildRen);
            });
            all.removeAll(children);
        }
        return children;
    }

    private void associateRole(TRolePermissionRel rel, List<PermissionNodeVO> nodes){
        nodes.stream().forEach(n->{
            if(n.getId().equals(rel.getPermissionId())){
                n.setRoleId(rel.getRoleId());
            }
            if(n.getRoleId()==null){
                associateRole(rel, n.getChildren());
            }
        });
    }
}
